﻿using System.Data.Entity;
using System.Linq.Expressions;
using BizModels;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using DataModel;
using IRepositories;
using BizModels.Common;

namespace Repositories
{
    public class BoardRepository : RepositoryBase, IBoardRepository
    {
        public BoardRepository()
        {
            Context = new HinokyEntities();
        }

        /// <summary>
        /// Article 등록하기
        /// </summary>
        public int AddBoard(BoardT board)
        {
            AddCategories(board);

            var categoryListData = Context.Categories.ToList();

            var data = new Board
            {
                Title = board.Title,
                Contents = board.Contents,
                InsertDate = DateTime.Now,
                UpdateDate = null,
                SearchTag = board.SearchTag,
                IsDisplay = board.IsDisplay,
                IsDelete = false,
                InsertUserKey = board.InsertUser.UserKey,
                UpdateUserKey = null
            };

            if (board.Categories != null && board.Categories.Count > 0)
            {
                foreach (var category in board.Categories)
                {
                    if (string.IsNullOrEmpty(category)) continue;

                    var item = categoryListData.FirstOrDefault(s => s.CategoryName.Equals(category));
                    data.Categories.Add(item);
                }
            }
            else
            {
                var item = categoryListData.FirstOrDefault(s => s.CategoryName.Equals(string.Empty));
                data.Categories.Add(item);
            }

            Context.Board.Add(data);

            Context.SaveChanges();

            return data.Idx;
        }

        /// <summary>
        /// Article 읽기
        /// </summary>
        public BoardT GetBoard(BoardSearchSingleT searchSingleItemT)
        {            
            var board = new BoardT();

            var query = Context.Board.Where(s => s.Idx.Equals(searchSingleItemT.Idx));

            if (searchSingleItemT.IsIncludeDeleteItem)
                query = query.Where(s => s.IsDelete);

            if (!searchSingleItemT.IsIncludeDisplayNoneItem)
                query = query.Where(s => s.IsDisplay);

            var boardData = query.SingleOrDefault();

            if (boardData == null) return board;
            
            board.Idx = boardData.Idx;
            board.Title = boardData.Title;
            board.Contents = boardData.Contents;
            board.Categories = boardData.Categories.Select(s => s.CategoryName).ToList();
            board.InsertDate = boardData.InsertDate;
            board.UpdateDate = boardData.UpdateDate;
            board.SearchTag = boardData.SearchTag;
            board.IsDisplay = boardData.IsDisplay;
            board.IsDelete = false;
            board.InsertUser.UserKey = boardData.InsertUserKey;
            board.UpdateUser.UserKey = boardData.UpdateUserKey == null ? 0 : (int)boardData.UpdateUserKey;

            // 등록자 정보 가져오기
            var insertUserData = Context.Members.SingleOrDefault(s => s.UserKey == board.InsertUser.UserKey);

            if (insertUserData != null)
            {
                board.InsertUser.UserID = insertUserData.Id;
                board.InsertUser.Name = insertUserData.Name;
            }

            // 수정자 정보 가져오기
            if (board.UpdateUser.UserKey == 0) return board;

            var updateUserData = Context.Members.SingleOrDefault(s => s.UserKey == board.UpdateUser.UserKey);

            if (updateUserData == null) return board;

            board.UpdateUser.UserID = updateUserData.Id;
            board.UpdateUser.Name = updateUserData.Name;


            return board;
        }

        /// <summary>
        /// 게시물을 등록한다.
        /// </summary>
        public int SetBoard(BoardT board)
        {
            AddCategories(board);

            var data = Context.Board.SingleOrDefault(s => s.Idx.Equals(board.Idx));

            if (data == null) return 0;

            data.Title = board.Title;
            data.Contents = board.Contents;
            data.SearchTag = board.SearchTag;
            data.UpdateDate = DateTime.Now;
            data.UpdateUserKey = board.UpdateUser.UserKey;
            data.IsDisplay = board.IsDisplay;

            var categoryList = Context.Categories.Where(s => board.Categories.Contains(s.CategoryName)).ToList();

            data.Categories.Clear();
            data.Categories = categoryList;

            Context.SaveChanges();

            return board.Idx;
        }

        public int RemoveBoard(int id)
        {
            var data = Context.Board.SingleOrDefault(s => s.Idx.Equals(id));

            if (data == null) return 0;

            // 게시글과 연결된 카테고리를 삭제한다.
            data.Categories.Clear();

            data.IsDelete = true;

            return Context.SaveChanges();
        }

        public List<BoardT> GetBoardList(BoardSearchT boardSearchT)
        {
            Context = new HinokyEntities();

            var query = GetBoardListQuery(boardSearchT);

            var dataList = query.Select(s => new BoardT
            {
                Idx = s.Idx,
                Title = s.Title,
                Contents = s.Contents,
                InsertDate = s.InsertDate,
                UpdateDate = s.UpdateDate,
                SearchTag = s.SearchTag,
                IsDisplay = s.IsDisplay,
                IsDelete = s.IsDelete,
                InsertUser = new MemberT{ UserKey = s.InsertUserKey },
                UpdateUser = new MemberT { UserKey = s.UpdateUserKey == null ? 0 : (int)s.UpdateUserKey },
            }).Skip((boardSearchT.PageIndex - 1) * boardSearchT.PageSize).Take(boardSearchT.PageSize).ToList();

            // 회원정보를 읽어서 User정보 객체에 정보를 담아준다.
            var memberKeyList = dataList.Select(s => s.UpdateUser.UserKey).Union(dataList.Select(t => t.InsertUser.UserKey)).ToList();
            var memberData = Context.Members.Where(s => memberKeyList.Contains(s.UserKey)).ToList();

            // 등록자 정보를 담는다.
            foreach (var data in dataList)
            {
                var userInfo = memberData.FirstOrDefault(s => s.UserKey == data.InsertUser.UserKey);

                if (userInfo != null)
                {
                    data.InsertUser.UserID = userInfo.Id;
                    data.InsertUser.Name = userInfo.Name;
                }
            }

            // 수정자 정보를 담는다.
            foreach (var data in dataList)
            {
                if(data.UpdateUser.UserKey == 0) continue;

                var userInfo = memberData.FirstOrDefault(s => s.UserKey == data.UpdateUser.UserKey);

                if (userInfo != null)
                {
                    data.InsertUser.UserID = userInfo.Id;
                    data.InsertUser.Name = userInfo.Name;
                }
            }


            return dataList;
        }

        public int GetBoardListCount(BoardSearchT boardSearchT)
        {
            Context = new HinokyEntities();

            var query = GetBoardListQuery(boardSearchT);

            return query.Count();
        }

        private void AddCategories(BoardT board)
        {
            Context = new HinokyEntities();

            if (board.Categories == null) return;

            var categoryList = Context.Categories.ToList();

            foreach (var category in board.Categories)
            {
                if (!categoryList.Any(s => s.CategoryName.Equals(category)))
                {
                    Context.Categories.Add(new Categories
                    {
                        CategoryName = category,
                        InsertDate = DateTime.Now,
                        OrderNum = 0
                    });
                }
            }

            Context.SaveChanges();
        }

        private IQueryable<Board> GetBoardListQuery(BoardSearchT boardSearchT)
        {
            var query = Context.Board.Include(board => board.Categories).OrderByDescending(s => s.Idx).Where(s => s.Idx > 0);

            // 전체 카테고리를 가져올 경우가 아닐 경우
            if (boardSearchT.Category != "*")
                query = query.Where(s => s.Categories.Any(t => t.CategoryName == boardSearchT.Category));

            // 검색어 Filter
            if (!string.IsNullOrEmpty(boardSearchT.SearchText))
                query = query.Where(s => s.Title.Contains(boardSearchT.SearchText) || s.SearchTag.Contains(boardSearchT.SearchText));

            query = !boardSearchT.IsIncludeDisplayNoneItem ? query.Where(s => s.IsDisplay) : query;

            query = boardSearchT.IsIncludeDeleteItem ? query.Where(s => s.IsDelete) : query.Where(s => s.IsDelete == false);

            return query;
        }
    }
}
